package com.rfid.sockethelper;

import android.net.Uri;

import com.google.gson.Gson;
import com.rfid.DirectoryBean;
import com.rfid.event.ProgressEvent;

import org.greenrobot.eventbus.EventBus;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;

public class IOHelper {
    
    public static short CMD_STR = 0X0A01;

    public static short CMD_HEART = 0X00F1;

    public static short CMD_QUERY_CONFIGS = 0X00F2;
    public static short CMD_RESPON_CONFIGS = 0X00F3;
    public static short CMD_PULL_CONFIG = 0X00F4;
    public static short CMD_SET_CONFIG = 0X00F5;
    //发文件，传文件名也可能带路径
    public static short CMD_SEND_FILE = 0X00F6;
    //指请求远端文件列表
    public static short CMD_REQ_FILE_LIST = 0X0AF1;
    //发送文件列表
    public static short CMD_SEND_FILE_LIST = 0X0AF2;
    //请求指向性文件
    public static short CMD_REQ_FILE = 0X0AF3;
    //推送文件到对方指定位置
    public static short CMD_SET_FILE = 0X0AF4;
    //删除指定文件
    public static short CMD_DELETE_FILE = 0X0AF5;

    public static void closeServerSocket(ServerSocket serverSocket) {
        if (serverSocket != null) {
            try {
                serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                serverSocket = null;
            }
        }
    }

    public static void closeSocket(Socket socket) {
        if (socket != null) {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                socket = null;
            }
        }
    }

    public static void closeInputStream(InputStream inputStream) {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                inputStream = null;
            }
        }
    }

    public static void closeOutputStream(OutputStream outputStream) {
        if (outputStream != null) {
            try {
                outputStream.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                outputStream = null;
            }
        }
    }
    
    public static void sendHeart(OutputStream outputStream) throws IOException {
        if (outputStream == null) {
            return;
        }
        System.out.println("sendHeart");
        DataOutputStream dos = new DataOutputStream(outputStream);
        dos.writeShort(CMD_HEART);
    }

    public static void writeText(OutputStream outputStream, String text) throws IOException {
        if (outputStream == null || text == null || text.length() == 0) {
            return;
        }
        DataOutputStream dos = new DataOutputStream(outputStream);
        dos.writeShort(CMD_STR);
        byte data[] = text.getBytes("UTF-8");
        dos.writeInt(data.length);
        dos.write(data);
    }

    public static String readText(InputStream inputStream) throws IOException {
        if (inputStream == null) {
            return null;
        }
        DataInputStream din = new DataInputStream(inputStream);
        short cmd = din.readShort();
        if (cmd == CMD_HEART) {
            System.out.println("CMD_HEART");
            return null;
        } else if(cmd != CMD_STR) {
            byte[] bytes = new byte[inputStream.available()];
            int length = inputStream.read(bytes);
            return new String(bytes, 0, length, "utf-8");
        }
        int len = din.readInt();
        byte buffer[] = new byte[len];
        din.readFully(buffer);
        return new String(buffer, 0, len, "utf-8");
    }

    public static short readCmd(InputStream inputStream) throws IOException {
        if (inputStream == null) {
            return 0;
        }
        DataInputStream din = new DataInputStream(inputStream);
        return din.readShort();
    }

    public static String readString(InputStream inputStream) throws IOException {
        if (inputStream == null) {
            return null;
        }
        DataInputStream din = new DataInputStream(inputStream);
        int len = din.readInt();
        byte buffer[] = new byte[len];
        din.readFully(buffer);
        return new String(buffer, 0, len, "utf-8");
    }

    public static void writeString(OutputStream outputStream, String text) throws IOException {
        if (outputStream == null) {
            return;
        }
        DataOutputStream dos = new DataOutputStream(outputStream);
        byte data[] = text.getBytes("UTF-8");
        dos.writeInt(data.length);
        dos.write(data);
    }

    public static void writeConfig(OutputStream outputStream, String name,String text) throws IOException {
        if (outputStream == null || text == null || text.length() == 0) {
            return;
        }
        DataOutputStream dos = new DataOutputStream(outputStream);
        dos.writeShort(CMD_SET_CONFIG);
        byte data[] = name.getBytes("UTF-8");
        dos.writeInt(data.length);
        dos.write(data);
        data = text.getBytes("UTF-8");
        dos.writeInt(data.length);
        dos.write(data);
    }

    public static void queryConfig(OutputStream outputStream, String name) throws IOException {
        if (outputStream == null) {
            return;
        }
        DataOutputStream dos = new DataOutputStream(outputStream);
        dos.writeShort(CMD_PULL_CONFIG);
        byte data[] = name.getBytes("UTF-8");
        dos.writeInt(data.length);
        dos.write(data);
    }

    public static void queryConfigNames(OutputStream outputStream) throws IOException {
        sendCmd(outputStream,CMD_QUERY_CONFIGS);
    }

    public static String readConfigNames(InputStream inputStream) throws IOException {
        return readString(inputStream);
    }

    public static void sendConfigNames(OutputStream outputStream,String text) throws IOException {
        DataOutputStream dos = new DataOutputStream(outputStream);
        dos.writeShort(CMD_RESPON_CONFIGS);
        writeString(outputStream,text);
    }

    public static boolean sendFile(OutputStream outputStream, String path) throws IOException {
        File file = new File(path);
        if (file.length() == 0) {
            return false;
        }
        String name = file.getName();
        System.out.println("sendFile name = " + name);
        DataOutputStream dos = new DataOutputStream(outputStream);
        dos.writeShort(CMD_SEND_FILE);
        byte nb[] = path.getBytes("UTF-8");
        dos.writeInt(nb.length);
        dos.write(nb);
        long total = file.length();
        dos.writeLong(total);
        FileInputStream fileInputStream = new FileInputStream(file);
        byte buffer[] = new byte[8096];
        int len = 0;
        ProgressEvent event = new ProgressEvent(total,0,ProgressEvent.TYPE_WRITE);
        EventBus.getDefault().post(event);
        int cnt = 0;
        long current = 0;
        while ((len = fileInputStream.read(buffer)) != -1) {
            dos.write(buffer,0,len);
            current = current + len;
            cnt++;
            if (cnt%3 == 0) {
                event = new ProgressEvent(total, current, ProgressEvent.TYPE_WRITE);
                EventBus.getDefault().post(event);
            }
        }
        event = new ProgressEvent(total, current, ProgressEvent.TYPE_WRITE);
        EventBus.getDefault().post(event);
        return true;
    }

    public static String readFile(InputStream inputStream,String directoryPath) throws IOException {
        if (inputStream == null) {
            System.out.println("inputStream == null");
            return "";
        }
        System.out.println(directoryPath);
        File pf = new File(directoryPath);
        if (!pf.exists()) {
            boolean mk = pf.mkdirs();
            System.out.println("mkdir = " + mk);
        }
        DataInputStream din = new DataInputStream(inputStream);
        int nlen = din.readInt();
        System.out.println("nlen = " + nlen);
        byte buffer[] = new byte[nlen];
        readFully(din,buffer,0,nlen);
        String pathName = new String(buffer,"UTF-8");
        System.out.println("readFile name = " + pathName);
        File file = new File(pathName);
        FileOutputStream fos = new FileOutputStream(directoryPath + "/" + file.getName());
        long total = din.readLong();
        System.out.println("total = " + total);
        int len = 0;
        buffer = new byte[8096];
        int rlen = 8096;
        if (total < rlen) {
            rlen = (int) total;
        }
        long t_total = total;
        int cnt = 0;
        ProgressEvent event = new ProgressEvent(total,0,ProgressEvent.TYPE_READ);
        EventBus.getDefault().post(event);
        System.out.println(Thread.currentThread().getName());
        while ((len = din.read(buffer,0,rlen)) != -1) {
            System.out.println("read len = " + len);
            fos.write(buffer,0,len);
            t_total = t_total - len;
            if (t_total <= 0) {
                break;
            }
            if (t_total < rlen) {
                rlen = (int) t_total;
            }
            cnt++;
            if (cnt%5 == 0) {
                event = new ProgressEvent(total, total - t_total, ProgressEvent.TYPE_READ);
                EventBus.getDefault().post(event);
            }
        }
        System.out.println("len = " + len);
        System.out.println("over > " + Thread.currentThread().getName());
        event = new ProgressEvent(total, total - t_total, ProgressEvent.TYPE_READ);
        EventBus.getDefault().post(event);
        return pathName;
    }

    public static boolean sendSetFile(OutputStream outputStream,String path,String rPath) throws IOException {
        File file = new File(path);
        if (!file.exists()) {
            return false;
        }
        DataOutputStream dos = new DataOutputStream(outputStream);
        dos.writeShort(CMD_SET_FILE);
        byte nb[] = rPath.getBytes("UTF-8");
        dos.writeInt(nb.length);
        dos.write(nb);
        long total = file.length();
        dos.writeLong(total);
        FileInputStream fileInputStream = new FileInputStream(file);
        byte buffer[] = new byte[8096];
        ProgressEvent event = new ProgressEvent(total,0,ProgressEvent.TYPE_WRITE);
        EventBus.getDefault().post(event);
        int cnt = 0;
        long current = 0;
        int len = 0;
        while ((len = fileInputStream.read(buffer)) != -1) {
            dos.write(buffer,0,len);
            current = current + len;
            cnt++;
            if (cnt%3 == 0) {
                event = new ProgressEvent(total, current, ProgressEvent.TYPE_WRITE);
                EventBus.getDefault().post(event);
            }
        }
        event = new ProgressEvent(total, current, ProgressEvent.TYPE_WRITE);
        EventBus.getDefault().post(event);
        return true;
    }

    public static String readSetFile(InputStream inputStream) throws IOException {
        DataInputStream din = new DataInputStream(inputStream);
        int nlen = din.readInt();
        System.out.println("nlen = " + nlen);
        byte buffer[] = new byte[nlen];
        readFully(din,buffer,0,nlen);
        String pathName = new String(buffer,"UTF-8");
        System.out.println("readFile name = " + pathName);
        File file = new File(pathName);
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        FileOutputStream fos = new FileOutputStream(file);
        long total = din.readLong();
        System.out.println("file total = " + total);
        int len = 0;
        buffer = new byte[8096];
        int rlen = 8096;
        if (total < rlen) {
            rlen = (int) total;
        }
        long t_total = total;
        int cnt = 0;
        ProgressEvent event = new ProgressEvent(total,0,ProgressEvent.TYPE_READ);
        EventBus.getDefault().post(event);
        while ((len = din.read(buffer,0,rlen)) != -1) {
            fos.write(buffer,0,len);
            System.out.println("rlen = " + rlen + "--- len = " + len + ",t_total = " + t_total);
            t_total = t_total - len;
            if (t_total <= 0) {
                break;
            }
            if (t_total < rlen) {
                rlen = (int) t_total;
            }
            cnt++;
            if (cnt%5 == 0) {
                event = new ProgressEvent(total, total - t_total, ProgressEvent.TYPE_READ);
                EventBus.getDefault().post(event);
            }
        }
        event = new ProgressEvent(total, total - t_total, ProgressEvent.TYPE_READ);
        EventBus.getDefault().post(event);
        return pathName;
    }

    public static void sendDeleteFile(OutputStream outputStream,String path) throws IOException {
        DataOutputStream dos = new DataOutputStream(outputStream);
        dos.writeShort(CMD_DELETE_FILE);
        byte nb[] = path.getBytes("UTF-8");
        dos.writeInt(nb.length);
        dos.write(nb);
    }

    public static String readDeleteFile(InputStream inputStream) throws IOException {
        String path = readString(inputStream);
        return path;
    }

    //请求获取远端路径下的列表
    public static void sendQueryFileList(OutputStream outputStream, String path) throws IOException {
        System.out.println("sendQueryFileList > " +(outputStream == null));
        if (outputStream == null) {
            return;
        }
        DataOutputStream dos = new DataOutputStream(outputStream);
        dos.writeShort(CMD_REQ_FILE_LIST);
        writeString(outputStream,path);
    }

    //读取远端请求的路径
    public static String readQueryFileList(InputStream inputStream) throws IOException {
        System.out.println("readQueryFileList");
        return readString(inputStream);
    }
    //发送请求的路径下的文件列表
    public static void sendFileList(OutputStream outputStream, DirectoryBean info) throws IOException {
        System.out.println("sendFileList " +info);
        if (outputStream == null) {
            return;
        }
        Gson gson = new Gson();
        DataOutputStream dos = new DataOutputStream(outputStream);
        dos.writeShort(CMD_SEND_FILE_LIST);
        writeString(dos,gson.toJson(info));
    }
    //接收读取远端发过来的文件列表
    public static String readFileList(InputStream inputStream) throws IOException {
        return readString(inputStream);
    }

    //请求获取文件
    public static void sendReqFileCmd(OutputStream outputStream,String path) throws IOException {
        if (outputStream == null) {
            return;
        }
        DataOutputStream dos = new DataOutputStream(outputStream);
        dos.writeShort(CMD_REQ_FILE);
        writeString(outputStream,path);
    }

    public static void readFully(InputStream in,byte b[], int off, int len) throws IOException {
        if (len < 0)
            throw new IndexOutOfBoundsException();
        int n = 0;
        while (n < len) {
            int count = in.read(b, off + n, len - n);
            if (count < 0)
                throw new EOFException();
            n += count;
        }
    }

    public static void sendCmd(OutputStream outputStream,short cmd) throws IOException {
        if (outputStream == null) {
            return;
        }
        System.out.println("sendCmd " + cmd);
        DataOutputStream dos = new DataOutputStream(outputStream);
        dos.writeShort(cmd);
    }

}
